#include <initializefunction.h>

#include "FrameAspectTypes.h"

static void RegisterTypes() {
	MetaType::RegisterType<CurveFragment>();
	MetaType::RegisterType<CurveFragmentList>();
	MetaType::RegisterType<CurveFunction>();
	MetaType::RegisterType<CurveFunctionList>();

	MetaType::RegisterStreamOperator<CurveFragment>();
	MetaType::RegisterStreamOperator<CurveFragmentList>();
	MetaType::RegisterStreamOperator<CurveFunction>();
	MetaType::RegisterStreamOperator<CurveFunctionList>();
}

INITIALIZE_FUN(RegisterTypes)

bool CurveFragment::operator==(const CurveFragment & other) const
{
	return other.type == this->type && other.p == this->p;
}

bool CurveFragment::operator!=(const CurveFragment & other) const
{
	return !operator==(other);
}

void CurveFragment::SetStraght(Point2F begin, Point2F end)
{
	type = Straght;
	p[0] = begin;
	p[1] = end;
}

void CurveFragment::SetCurve(Point2F begin, Point2F con, Point2F end)
{
	type = Curve;
	p[0] = begin;
	p[1] = con;
	p[2] = end;
}

void CurveFragment::SetQuadCurve(Point2F begin, Point2F con1, Point2F con2, Point2F end)
{
	type = QuadCurve;
	p[0] = begin;
	p[1] = con1;
	p[2] = con2;
	p[3] = end;
}

CurveFragment::Type CurveFragment::GetType() const
{
	return type;
}

Point2F CurveFragment::GetPoint(int index) const
{
	return p[index];
}

 DataInputStream & operator>>(DataInputStream & s, CurveFragment & c)
{
	 s >> c.type;
	 for (int i = 0; i < CurveFragment::point_size; i++)
	 {
		 s >> c.p[i];
	 }
	 return s;
}

 DataOutputStream & operator<<(DataOutputStream & s, const CurveFragment & c)
{
	 s << c.type;
	 for (int i = 0; i < CurveFragment::point_size; i++)
	 {
		 s << c.p[i];
	 }
	 return s;
}

 DataInputStream & operator>>(DataInputStream & s, CurveFunction & c)
{
	 s >> c.curve;
	 return s;
}

 DataOutputStream & operator<<(DataOutputStream & s, const CurveFunction & c)
{
	 s << c.curve;
	 return s;
}

 float CurveFunction::operator()(float x, bool * valid) const
 {
	 return 0.0f;
 }

 bool CurveFunction::operator==(const CurveFunction & other) const
 {
	 return this->curve == other.curve;
 }

 bool CurveFunction::operator!=(const CurveFunction & other) const
 {
	 return !operator==(other);
 }

 const CurveFragmentList & CurveFunction::GetCurve() const
{
	return curve;
}

 CurveFunctionCreator & CurveFunctionCreator::Begin(float x, float y)
 {
	 result = {};
	 current = {x,y};

	 return *this;
 }

 CurveFunctionCreator & CurveFunctionCreator::LineTo(float dx, float y)
 {
	 CurveFragment c;
	 Point2F temp = current;
	 current[0] += dx;
	 current[1] = y;
	 c.SetStraght(temp, current);
	 result.curve.push_back(c);

	 return *this;
 }

 CurveFunctionCreator & CurveFunctionCreator::CurveTo(float dx, float y, float cx, float cy)
 {
	 CurveFragment c;
	 Point2F temp = current;
	 current[0] += dx;
	 current[1] = y;
	 c.SetCurve(temp, {cx,cy}, current);
	 result.curve.push_back(c);

	 return *this;
 }

 CurveFunctionCreator & CurveFunctionCreator::QuadCurveTo(float dx, float y, float c1x, float c1y, float c2x, float c2y)
 {
	 CurveFragment c;
	 Point2F temp = current;
	 current[0] += dx;
	 current[1] = y;
	 c.SetQuadCurve(temp, { c1x,c1y }, { c2x,c2y }, current);
	 result.curve.push_back(c);

	 return *this;
 }

 const CurveFunction & CurveFunctionCreator::End()
 {
	 current = {};
	 auto temp = result;
	 result = {};
	 return temp;
 }
